#include <Arduino.h>
#include "HX711.h"
#include <Wire.h>
#include <U8g2lib.h>
#include <ESP32Servo.h> // ESP32 专用舵机库
Servo myServo1;         // 创建舵机对象
Servo myServo2;         // 创建舵机对象
Servo myServo3;         // 创建舵机对象
Servo myServo4;         // 创建舵机对象
#define SDA_PIN 32      // ESP32为了预留端口给LAN8720
#define SCL_PIN 33
U8G2_SH1106_128X64_NONAME_1_HW_I2C u8g2(U8G2_R0, /* SCL= */ SCL_PIN, /* SDA= */ SDA_PIN, /* reset=*/U8X8_PIN_NONE);
// HX711 circuit wiring
const int LOADCELL_DOUT_PIN = 16;
const int LOADCELL_SCK_PIN = 4;

HX711 scale;
// 校准参数
#include <WiFi.h>
#include <HTTPClient.h>
#include "OneNETSDK.h"
static WiFiClient espClient;
char DEV_ChipID[16];
#define PRODUCT_KEY "TxY85O17Os"
#define DEVICE_SECRET "cV/Jb2cXMTfTqTlBpXHnExWNq3dv70VpUc07tXFrs6E="//onenet密钥
const char *ssid = "styn-iot";
const char *password = "st7713926813";
TaskHandle_t CoreTask1; // 声明CoreTask1任务句柄，用于在核心1上运行任务
TaskHandle_t CoreTask2; // 声明CoreTask2任务句柄，用于在核心2上运行任务
TaskHandle_t CoreTask3; // 声明CoreTask3任务句柄，用于在核心2上运行任务
TaskHandle_t CoreTask4;
TaskHandle_t CoreTask5;
TaskHandle_t CoreTask6;
float weight;
int num = 0;
int fja=50;
int fjb=150;
int fjc=200;
// 定义舵机数量及引脚
const int SERVO_COUNT = 4;                            // 控制4个舵机
const int SERVO_PINS[SERVO_COUNT] = {26, 27, 14, 12}; // GPIO列表

// SG90 舵机参数
const int PWM_FREQ = 50;       // 50Hz (周期20ms)
const int PWM_RESOLUTION = 16; // 16位分辨率(0~65535)

// 计算指定角度对应的占空比
int calculateDuty(int degree)
{
  degree = constrain(degree, 0, 180); // 限制角度范围
  int pulseWidth = map(degree, 0, 180, 500, 2500);
  return (int)((float)pulseWidth / (1000000.0 / PWM_FREQ) * (1 << PWM_RESOLUTION));
}

// 设置舵机角度
void setServoAngle(int servoIndex, int angle)
{
  if (servoIndex >= 0 && servoIndex < SERVO_COUNT)
  {
    ledcWrite(servoIndex, calculateDuty(angle));
  }
}
int getNumByRange(float x,int a,int b,int c)
{
  if (x >= 2 && x < a)
  {
    return 0;
  }
  else if (x >= a && x < b)
  {
    return 1;
  }
  else if (x >= b && x <= c)
  {
    return 2; // 注意：根据需求这里应该是2还是3？
  }
  else if (x > c)
  {
    return 3;
  }
  else
  {
    return -1; // 处理x为负数的情况
  }
}
void task1(void *pvParameters)
{
  Serial.begin(115200);
  scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
  scale.set_scale(-428); // 设置校准系数
  scale.tare();          // 空载归零
  while (1)
  {
    if (scale.wait_ready_timeout(1000))
    {
      weight = scale.get_units(10);
      if (weight < 0)
      {
        weight = 0;
      }
      num = getNumByRange(weight,fja,fjb,fjc);
    }
    else
    {
      Serial.println("HX711 无响应");
    }
    vTaskDelay(100);
  }
}
void task2(void *pvParameters)
{
  char toptxt[24], downtxt[24], txt1[24], txt2[24];
  Wire.begin(32, 33);
  u8g2.begin();
  u8g2.enableUTF8Print();
  u8g2.setFontMode(0);
  u8g2.firstPage();
  do
  {
    u8g2.drawFrame(0, 0, u8g2.getDisplayWidth(), 16);
    u8g2.setFont(u8g2_font_wqy14_t_gb2312b);
    u8g2.setCursor(12, 13);
    u8g2.print(F("英斯派尔IoT模组"));
    u8g2.setCursor(0, 62);
    u8g2.print(F("物联模块启动中"));
    // u8g2.print((class __FlashStringHelper *)logotxt);
  } while (u8g2.nextPage());
  while (1)
  {
    snprintf(toptxt, 24, "重量:%3.2f克", weight);
    snprintf(txt1, 24, "|---|---|---|---|%s"," ");
    snprintf(txt2, 24, "  0    %d    %d    %d",fja,fjb,fjc);
    if (num==0)
    {
      snprintf(downtxt, 24, "闸口1打开%s"," ");
    }
        if (num==1)
    {
      snprintf(downtxt, 24, "闸口2打开%s"," ");
    }
        if (num==2)
    {
      snprintf(downtxt, 24, "闸口3打开%s"," ");
    }
        if (num==3)
    {
      snprintf(downtxt, 24, "闸口4打开%s"," ");
    }
        if (num==-1)
    {
      snprintf(downtxt, 24, "闸口全开,无物品在称上%s"," ");
    } 
    u8g2.setPowerSave(0);
    u8g2.firstPage();
    do
    {
      // u8g2.setFont(u8g2_font_wqy14_t_gb2312b);
      u8g2.drawUTF8(2, 12, toptxt);
      u8g2.drawUTF8(0, 28, txt1);
      u8g2.drawUTF8(0, 44, txt2);
      u8g2.drawUTF8(0, 62, downtxt);
    } while (u8g2.nextPage());
    vTaskDelay(500);
  }
}

void task3(void *pvParameters)
{
  Serial.begin(115200);

  // 初始化所有舵机PWM通道
  for (int i = 0; i < SERVO_COUNT; i++)
  {
    ledcSetup(i, PWM_FREQ, PWM_RESOLUTION); // 每个舵机独立通道
    ledcAttachPin(SERVO_PINS[i], i);        // 绑定引脚到对应通道
    setServoAngle(i, 0);                    // 初始化为0度
  }

  Serial.println("多舵机系统初始化完成");
  while (1)
  {
    switch (num)
    {
    case 0:
      setServoAngle(0, 90);
      setServoAngle(1, 0);
      setServoAngle(2, 0);
      setServoAngle(3, 0);
      break;
    case 1:
      setServoAngle(1, 90);
      setServoAngle(0, 0);
      setServoAngle(2, 0);
      setServoAngle(3, 0);
      break;
    case 2:
      setServoAngle(2, 90);
      setServoAngle(0, 0);
      setServoAngle(1, 0);
      setServoAngle(3, 0);
      break;
    case 3:
      setServoAngle(3, 90);
      setServoAngle(0, 0);
      setServoAngle(1, 0);
      setServoAngle(2, 0);
      break;
    default:
      setServoAngle(0, 0);
      setServoAngle(1, 0);
      setServoAngle(2, 0);
      setServoAngle(3, 0);
      break;
    }
    vTaskDelay(1000);
  }
}
void task4(void *pvParameters)
{
  while (1)
  {
    OneNETSDK::send("weight", weight);
    OneNETSDK::loop();
   vTaskDelay(500);
  }
  }
  void unlock1(JsonVariant fjaing)
{
  int w1_on = fjaing["fjaing"];
  fja=w1_on;
   Serial.println(w1_on);
  OneNETSDK::loop();
}
  void unlock2(JsonVariant fjbing)
{
  int w1_on = fjbing["fjbing"];
  fjb=w1_on;
   Serial.println(w1_on);
  OneNETSDK::loop();
}
  void unlock3(JsonVariant fjcing)
{
  int w1_on = fjcing["fjcing"];
  fjc=w1_on;
   Serial.println(w1_on);
  OneNETSDK::loop();
}
void setup()
{
  Serial.begin(115200);  // 初始化串口
  WiFi.begin(ssid, password);
  uint32_t chipId = 0;
  for (int i = 0; i < 17; i = i + 8)
  {
    chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
  }
  snprintf(DEV_ChipID, 16, "ELE-%06X", chipId);

  OneNETSDK::begin(espClient, PRODUCT_KEY, DEV_ChipID, DEVICE_SECRET);
  vTaskDelay(5000);
  OneNETSDK::bindData("fjaing", unlock1);
  OneNETSDK::bindData("fjbing", unlock2);
  OneNETSDK::bindData("fjcing", unlock3);
  xTaskCreatePinnedToCore(
      task1,      // 实现任务的函数名称
      "HQQX",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配16K够不够
      NULL,       // 任务输入参数，可以为NULL
      0,          // 任务优先级，3最高，0最低
      &CoreTask1, // 任务句柄，头部已定义，亦可以为NULL
      0);         // 任务运行的内核ID（0或者1）
  xTaskCreatePinnedToCore(
      task2,      // 实现任务的函数名称
      "U8G2",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配16K够不够
      NULL,       // 任务输入参数，可以为NULL
      0,          // 任务优先级，3最高，0最低
      &CoreTask2, // 任务句柄，头部已定义，亦可以为NULL
      0);         // 任务运行的内核ID（0或者1）
  xTaskCreatePinnedToCore(
      task3,      // 实现任务的函数名称
      "BDHQ",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配16K够不够
      NULL,       // 任务输入参数，可以为NULL
      1,          // 任务优先级，3最高，0最低
      &CoreTask3, // 任务句柄，头部已定义，亦可以为NULL
      0);         // 任务运行的内核ID（0或者1）
              xTaskCreatePinnedToCore(
      task4,      // 实现任务的函数名称
      "SEND",     // 任务的任何名称，按实际功能起名
      16384,      // 分配给任务的堆栈大小，以字节为单位，先尝试一下分配64K够不够
      NULL,       // 任务输入参数，可以为NULL
      1,          // 任务优先级，3最高，0最低
      &CoreTask4, // 任务句柄，头部已定义，亦可以为NULL
      1);         // 任务运行的内核ID（0或者1）
      OneNETSDK::loop();
}

void loop()
{
  OneNETSDK::loop();
  vTaskDelay(500);
}
